package com.dingreading.cloud.common.util;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.dingreading.cloud.common.util.wechat.WxPKCS7Encoder;
import com.sun.jersey.core.util.Base64;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.io.FileOutputStream;
import java.security.AlgorithmParameters;
import java.security.Security;
import java.security.spec.AlgorithmParameterSpec;

/**
 * 小程序工具
 */
public class WxMiniUtil {

    private WxMiniUtil() {
    }

    private static class Instance {
        private static WxMiniUtil wxMiniUtil = new WxMiniUtil();

        private static WxMiniUtil getWxMiniUtil() {
            return wxMiniUtil;
        }
    }

    public static WxMiniUtil Init() {
        return Instance.getWxMiniUtil();
    }

    /**
     * 解密用户手机号
     *
     * @param session_key   session_key
     * @param encryptedData 包括敏感数据在内的完整用户信息的加密数据
     * @param iv            加密算法的初始向量
     * @return JSONObject
     */
    public static final JSONObject getPhoneNumber(String session_key, String encryptedData, String iv) {
        try {
            byte[] encData = Base64.decode(encryptedData);
            byte[] ivByte = Base64.decode(iv);
            byte[] key = Base64.decode(session_key);

            AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivByte);
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
            cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);

            String str = new String(cipher.doFinal(encData), "UTF-8");
            return JSON.parseObject(str);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    static {
        //BouncyCastle是一个开源的加解密解决方案，主页在http://www.bouncycastle.org/
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * AES解密
     *
     * @param data           //密文，被加密的数据
     * @param key            //秘钥
     * @param iv             //偏移量
     * @param encodingFormat //解密后的结果需要进行的编码
     * @param type           //0 是其他 1是微信步数
     * @return
     * @throws Exception
     */
    public String decrypt(String key, String data, String iv, String encodingFormat, Integer type) throws Exception {
        //被加密的数据
        byte[] dataByte = Base64.decode(data);
        //加密秘钥
        byte[] keyByte = Base64.decode(key);
        //偏移量
        byte[] ivByte = Base64.decode(iv);

        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");

            SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");

            AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
            parameters.init(new IvParameterSpec(ivByte));

            cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化

            byte[] resultByte = cipher.doFinal(dataByte);
            if (null != resultByte && resultByte.length > 0) {
                if (type == 1) {
                    return new String(WxPKCS7Encoder.decode(resultByte));
                } else {
                    return new String(resultByte, encodingFormat);
                }
            }
            return null;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("微信小程序获取手机号：小程序解析出错");
        }
        return null;
    }

    /**
     * 小程序 URL Link
     *
     * @param path  通过 URL Link 进入的小程序页面路径
     * @param query 通过 URL Link 进入的小程序页面路径
     */
    public String getUrlLIng(String accessToken, String path, String query) throws Exception {
        JSONObject params = new JSONObject();
        params.put("query", query);
        if (StringUtils.isNotBlank(path))
            params.put("path", path);
        String jsonString = params.toJSONString();
        String url = "https://api.weixin.qq.com/wxa/generate_urllink?access_token=" + accessToken;
        String result = HttpUtils.post(url, jsonString);
        if (StringUtils.isBlank(result))
            throw new DescribeException(500, "获取小程序UrlLing失败");

        JSONObject jsonObject = JSONObject.parseObject(result);
        Integer errcode = jsonObject.getInteger("errcode");
        String errmsg = jsonObject.getString("errmsg");
        if (null == errcode || !errcode.equals(0))
            throw new DescribeException(500, "获取小程序UrlLing失败！返回结果：" + errmsg);
        String urlLink = jsonObject.getString("url_link");
        return urlLink;
    }

    /**
     * 小程序 URL Scheme
     *
     * @param path  通过 URL Link 进入的小程序页面路径
     * @param query 通过 URL Link 进入的小程序页面路径
     */
    public String getUrlScheme(String accessToken, String path, String query) throws Exception {
        JSONObject params = new JSONObject();

        JSONObject jumpObj = new JSONObject();
        if (StringUtils.isNotBlank(path))
            jumpObj.put("path", path);
        if (StringUtils.isNotBlank(query))
            jumpObj.put("query", "userUid=" + query);

        params.put("jump_wxa", jumpObj);
        String jsonString = params.toJSONString();
        String url = "https://api.weixin.qq.com/wxa/generatescheme?access_token=" + accessToken;
        String result = HttpUtils.post(url, jsonString);
        if (StringUtils.isBlank(result))
            throw new DescribeException(500, "获取小程序UrlLing失败");

        JSONObject jsonObject = JSONObject.parseObject(result);
        Integer errcode = jsonObject.getInteger("errcode");
        String errmsg = jsonObject.getString("errmsg");
        if (null == errcode || !errcode.equals(0))
            throw new DescribeException(500, "获取小程序UrlScheme失败！返回结果：" + errmsg);
        String urlLink = jsonObject.getString("openlink");
        return urlLink;
    }

    /**
     * 获取不限制的小程序码
     *
     * @param page  默认是主页，页面 page，例如 pages/index/index，根路径前不要填加 /，不能携带参数
     * @param scene 最大32个可见字符，只支持数字，大小写英文以及部分特殊字符：!#$&'()*+,/:;=?@-._~
     * @param width 默认430，二维码的宽度，单位 px，最小 280px，最大 1280px
     */
    public JSONObject getCodeUnLimit(String accessToken, String page, String scene, int width) throws Exception {
        JSONObject params = new JSONObject();
        if (StringUtils.isNotBlank(page))
            params.put("page", page);
        if (StringUtils.isNotBlank(scene))
            params.put("scene", scene);
        params.put("width", width);
        // 正式版为 "release"，体验版为 "trial"，开发版为 "develop"
//        params.put("env_version", "trial");

        String jsonString = params.toJSONString();
        String url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + accessToken;
        JSONObject result = HttpUtils.xcxBytesPost(url, jsonString);
        return result;
    }

    /**
     * 手机号验证
     *
     * @return 手机号获取凭证
     */
    public String getUserPhoneNumber(String accessToken, String code) throws Exception {
        JSONObject params = new JSONObject();
        params.put("code", code);

        String jsonString = params.toJSONString();
        String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + accessToken;
        String result = HttpUtils.post(url, jsonString);

        JSONObject jsonObject = JSONObject.parseObject(result);
        Integer errcode = jsonObject.getInteger("errcode");
        String errmsg = jsonObject.getString("errmsg");
        if (null == errcode || !errcode.equals(0))
            throw new DescribeException(500, "获取小程序用户手机号失败！" + errcode + "，" + errmsg);
        JSONObject phoneInfo = jsonObject.getJSONObject("phone_info");
        // 用户绑定的手机号（国外手机号会有区号）
//        String phoneNumber = phoneInfo.getString("phoneNumber");
        // 没有区号的手机号
        String purePhoneNumber = phoneInfo.getString("purePhoneNumber");
        return purePhoneNumber;
    }

    /**
     * 获取小程序登录用户信息
     * <p>
     * https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/user-login/code2Session.html
     */
    public JSONObject getUnionidAndOpenid(String appid, String secret, String code) throws Exception {
        String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appid + "&secret=" + secret + "&js_code=" + code + "&grant_type=authorization_code";
        String result = HttpUtils.get(url);

        JSONObject jsonObject = JSONObject.parseObject(result);
        Integer errcode = jsonObject.getInteger("errcode");
        String errmsg = jsonObject.getString("errmsg");
        if (errcode != null && !errcode.equals(0))
            throw new DescribeException(500, "获取小程序登录用户信息失败！" + errcode + "，" + errmsg);

        return jsonObject;
    }

    /**
     * 字节流图片下载到本地
     */
    public String buff2Image(byte[] img, String... fileNames) throws Exception {
        String fileName = "";
        if (fileNames != null && fileNames.length > 0) {
            fileName = fileNames[0] + ".jpg";
        } else {
            fileName = KitUtil.getUuid() + ".jpg";
        }

        // 图片基础保存路径
        String baseDir = "/home/www/DingSpaceOS/public/uploadimgs/wxminicode/";
        // 年/月/日
        String ymd = DateUtil.datetime(DateUtil.DEFAULT_DATE_FORMAT_SLASH);
        // 文件夹不存在则创建
        File fileDir = new File(baseDir + ymd);
        if (!fileDir.exists()) {
            fileDir.mkdirs();
        }

        String tagSrc = baseDir + ymd + "/" + fileName;
        FileOutputStream fout = new FileOutputStream(tagSrc);
        //将字节写入文件
        fout.write(img);
        fout.close();
        return "wxminicode" + "/" + ymd + "/" + fileName;
    }

}
